﻿Imports System.Linq.Expressions
Imports System.Text.RegularExpressions
Imports System.Collections.ObjectModel
Imports System.Reflection

Namespace Load

    ''' <summary>
    ''' イテレートクエリプロバイダー
    ''' </summary>
    ''' <remarks></remarks>
    Public Class IterateQueryProvider
        Inherits QueryProviderBase

        ''' <summary>
        ''' コンストラクタ
        ''' </summary>
        ''' <param name="r">モデルローダー</param>
        ''' <remarks></remarks>
        Public Sub New(r As ModelLoader)
            _loader = r
        End Sub

        ''' <summary>
        ''' ルートテーブルエイリアスを作成します
        ''' </summary>
        ''' <param name="t"></param>
        ''' <param name="q"></param>
        ''' <returns></returns>
        Protected Friend Overrides Function CreateRootTableAlias(t As System.Type, q As IQuery) As RootTableAlias
            Dim rt As RootTableAlias = MyBase.CreateRootTableAlias(t, q)

            rt.ParameterPrefix = Me.Loader.ParameterPrefix
            rt.LimitLevel = 0
            rt.CanLeftJoin = False
            rt.IgnoreProperty = Nothing

            Return rt
        End Function

        ''' <summary>
        ''' 読み込み完了時イベント
        ''' </summary>
        ''' <param name="lst"></param>
        ''' <param name="t"></param>
        ''' <param name="q"></param>
        ''' <remarks></remarks>
        Protected Friend Overrides Sub OnLoaded(lst As IList, t As Type, q As IQuery)
            If Me.Loader.WorkCascadeLevel = 0 Then Return

            Dim fn = GetType(IterateQueryProvider).GetMethod("CascadeExecute").MakeGenericMethod({t})
            fn.Invoke(Me, {lst, 0})
        End Sub

        ''' <summary>
        ''' カスケード実行します
        ''' </summary>
        ''' <typeparam name="MyT"></typeparam>
        ''' <param name="source"></param>
        ''' <param name="nowLevel"></param>
        ''' <remarks></remarks>
        Public Sub CascadeExecute(Of MyT)(source As IList(Of MyT), nowLevel As Integer)
            '上限判定
            If Me.Loader.WorkCascadeLevel <> -1 AndAlso nowLevel = Me.Loader.WorkCascadeLevel Then Return

            Dim queryList As New QueryableList(Of MyT)(Me.Loader, source)

            '上層読み込み
            For Each parentType As Type In (From el In GetType(MyT).ToTable.Columns Where el.IsParent AndAlso el.PropertyInfo.Equals(Me.Loader.MappingIgnoreProperty) = False Select el.PropertyInfo.PropertyType)
                '無限ループ回避判定
                If Me.Loader.WorkCascadeLevel = -1 AndAlso nowLevel <> 0 AndAlso parentType.Equals(GetType(MyT)) Then Continue For

                '読み込み＋再帰処理
                Dim pt As Type = parentType
                Dim recursionAct As Action(Of IList) =
                    Sub(parents)
                        Dim f As MethodInfo = GetType(IterateQueryProvider).GetMethod("CascadeExecute").MakeGenericMethod({pt})
                        f.Invoke(Me, {parents, nowLevel + 1})
                    End Sub

                'LoadParent Method
                '   args1  source As QueryableList(Of MyT)
                '   args2  Optional limitLevel As Integer = 0
                '   args3  Optional canLeftJoin As Boolean = False
                '   args4  Optional parentCallback As Action(Of IList) = Nothing
                Dim fn As MethodInfo = GetType(QueryableListExtension).GetMethod("LoadParent").MakeGenericMethod({GetType(MyT), pt})
                fn.Invoke(Nothing, {queryList, recursionAct})
            Next
        End Sub

    End Class

End Namespace
